package com.webank.wedatasphere.qualitis.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.jpa.domain.Specification;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAccessor;
import java.util.*;

public class CommUtils {


    /**
     *  获取前端传递的json对象--EasyUi过滤器
     * @param request
     * @return
     */
    public static JSONObject getJsonObject(HttpServletRequest request) {
        JSONObject changeBuilder = new JSONObject();
        String filterRules = request.getParameter("filterRules");
        if (StringUtils.isNotEmpty(filterRules)) {
            JSONArray filters = JSONArray.parseArray(filterRules);
            for (int i = 0; i < filters.size(); i++) {
                JSONObject item = filters.getJSONObject(i);
                changeBuilder.put(item.getString("field"), item.getString("value"));
            }
        }
        return changeBuilder;
    }

    /**
     *  获取前端传递的json对象--SpringDataJpa过滤器
     * @param request
     * @return
     */
    public static ExampleMatcher getSqlWhere(HttpServletRequest request) {
        ExampleMatcher withMatcher = ExampleMatcher.matching();
        String filterRules = request.getParameter("filterRules");
        if (StringUtils.isNotEmpty(filterRules)) {
            JSONArray filters = JSONArray.parseArray(filterRules);
            for (int i = 0; i < filters.size(); i++) {
                JSONObject item = filters.getJSONObject(i);
                // 模糊匹配
                withMatcher = withMatcher.withMatcher(item.getString("field"), ExampleMatcher.GenericPropertyMatchers.contains());
            }
        }
        return withMatcher;
    }


    public static JSONObject getJsonObject(String filterRules) {
        JSONObject changeBuilder = new JSONObject();
        if (StringUtils.isNotEmpty(filterRules)) {
            JSONArray filters = JSONArray.parseArray(filterRules);
            for (int i = 0; i < filters.size(); i++) {
                JSONObject item = filters.getJSONObject(i);
                changeBuilder.put(item.getString("field"), item.getString("value"));
            }
        }
        return changeBuilder;
    }

    public static ExampleMatcher getSqlWhere(String filterRules) {
        ExampleMatcher withMatcher = ExampleMatcher.matching();
        if (StringUtils.isNotEmpty(filterRules)) {
            JSONArray filters = JSONArray.parseArray(filterRules);
            for (int i = 0; i < filters.size(); i++) {
                JSONObject item = filters.getJSONObject(i);
                // 模糊匹配
                withMatcher = withMatcher.withMatcher(item.getString("field"), ExampleMatcher.GenericPropertyMatchers.contains());
            }
        }
        return withMatcher;
    }

    public static <T> Specification<T> tableFilterSpec(String filterRules, T t) {
        DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd").toFormatter();
        return (root, query, builder) -> {
            List<Predicate> predicates = new ArrayList<>();

            Field[] fields = t.getClass().getDeclaredFields();
            for (Field f : fields) {
                String field = f.getName();
                try {
                    Method method = t.getClass().getDeclaredMethod("get" + StringUtils.capitalize(field));
                    Object value = method.invoke(t);
                    if (value == null) {
                        continue;
                    }
                    // 整形全匹配
                    if (Number.class.isAssignableFrom(value.getClass())) {
                        predicates.add(builder.equal(root.get(field), value));
                        continue;
                    }
                    // 日期类型
                    if (Date.class.isAssignableFrom(value.getClass())) {
                        Date date = (Date) value;
                        predicates.add(builder.equal(root.get(field), date));
                        continue;
                    }
                    // 字符串模糊查询
                    predicates.add(builder.like(root.get(field), "%" + value + "%"));
                } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }

            if (StringUtils.isBlank(filterRules) || "[]".equals(filterRules)) {
                return builder.and(predicates.toArray(new Predicate[0]));
            }

            // 根据字段分组
            HashMap<String, List<String>> map = new HashMap<>();
            JSONArray filters = JSONArray.parseArray(filterRules);
            for (int i = 0; i < filters.size(); i++) {
                JSONObject item = filters.getJSONObject(i);
                String field = item.getString("field");
                String value = item.getString("value");
                if (map.containsKey(field)) {
                    List<String> list = map.get(field);
                    list.add(value);
                } else {
                    List<String> list = new ArrayList<>();
                    list.add(value);
                    map.put(field, list);
                }
            }

            // 对每个字段添加多条件过滤
            Set<String> keySet = map.keySet();
            for (String field : keySet) {
                List<String> list = map.get(field);

                // 整形全匹配
                if (Number.class.isAssignableFrom(root.get(field).getJavaType())) {
                    if (list.size() > 1) {
                        predicates.add(root.in(list));
                    } else {
                        predicates.add(builder.equal(root.get(field), list.get(0)));
                    }
                    continue;
                }
                // 日期过滤当天的数据
                if (Date.class.isAssignableFrom(root.get(field).getJavaType())) {
                    if (list.size() > 1) {
                        Instant startInstant = LocalDate.parse(list.get(0), formatter).atTime(0, 0, 0).atZone(ZoneId.systemDefault()).toInstant();
                        Instant endInstant = LocalDate.parse(list.get(1), formatter).atTime(0, 0, 0).atZone(ZoneId.systemDefault()).toInstant();
                        if (startInstant.isBefore(endInstant)) {
                            Instant tmpInstant = startInstant;
                            startInstant = endInstant;
                            endInstant = tmpInstant;
                        }
                        predicates.add(builder.greaterThanOrEqualTo(root.get(field), Date.from(endInstant)));
                        predicates.add(builder.lessThan(root.get(field), Date.from(startInstant)));
                    } else {
                        Instant instant = LocalDate.parse(list.get(0), formatter).atTime(0, 0, 0).atZone(ZoneId.systemDefault()).toInstant();
                        predicates.add(builder.greaterThanOrEqualTo(root.get(field), Date.from(instant)));
                        predicates.add(builder.lessThan(root.get(field), Date.from(instant.plus(1, ChronoUnit.DAYS))));
                    }
                    continue;
                }
                // 字符串模糊查询
                predicates.add(builder.like(root.get(field), "%" + list.get(0) + "%"));
            }

            return builder.and(predicates.toArray(new Predicate[0]));
        };
    }
}
